#ifndef _SESSION_H_
#define _SESSION_H_

#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>

#include "../../../../Common/PackageUtil.h"

using namespace std;
using boost::asio::ip::tcp;

enum LogicResult
{
	LogicNeedConnect,
	LogicNeedWrite,
	LogicWaitRead,

	LogicNormalData,
	LogicBroadcastData,
	LogicMulticastData,
	LogicNormalPlusMultiData,

	LogicError,
};

class Client
{
public:
	tcp::socket socket;
	tcp::endpoint *p_endpoint;
	bool is_connect;

public:
	Client(boost::asio::io_service &io_service);
	~Client();

	void Init(std::string server_ip, short port);
};

class Logic
{
public:
	Client *p_client;

	// use server and player id combination as key
	int server_key;
	unsigned int session_key;

	unsigned int *p_multicast_player_id;
	int multicast_player_num;
	int drop_info_len;

private:
	struct Common::PackageHead _package_head;
	Client _game_client;
	vector<char *> _package_head_list;

public:
	Logic(boost::asio::io_service &io_service);
	~Logic();

	int Init();

	int GetPackageNum(char *buf, int len);
	enum LogicResult ProcessUpStreamData(char *buf, int len);
	enum LogicResult ProcessDownStreamPackage(int index, char *&p_data, int &len);

	static int ServerKey(int server_type, int server_id);

private:
	int ParseHead(char *buf);
	int ServerKey();
	unsigned int SessionKey();
};

// class Session : public boost::enable_shared_from_this<Session>
class Session
{
public:
	Logic logic;

private:
	tcp::socket _socket;
	char _package[MAX_PACKAGE_SIZE];
	int _package_len;
	int _is_control;

public:
	Session(boost::asio::io_service &io_service);
	~Session();

	tcp::socket & Socket();
	void Start();
	void StartControl();

private:
	void HandleWrite(const boost::system::error_code &error);
	void HandleRead(const boost::system::error_code &error, size_t bytes_transferred);
	void HandleBackServerConnect(const boost::system::error_code& error);
	void HandleBackServerRead(const boost::system::error_code &error, size_t bytes_transferred);
	void HandleBackServerWrite(const boost::system::error_code& error);
	void WriteToBackServer();
	void DeleteSelf();
};

#endif
